# encoding: utf-8
# @File  : dun_03_chufashi.py
# @Author: wu shaofan
# @Date  :  2024/02/22
# @Desc : 网盾 触发式
import os
import time

import cv2
import pyautogui
import requests
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
import conftest
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium import webdriver


class  Dun03Chufashi:
    def __init__(self):
        # 设置 Chrome WebDriver 路径
        chrome_driver_path = conftest.BASE_DIR + '/tool/chromedriver.exe'
        # 创建 ChromeOptions 对象
        options = Options()
        options.add_experimental_option("excludeSwitches", ["enable-logging"])
        # 创建 Chrome WebDriver 服务
        service = Service(chrome_driver_path)
        # 创建 Chrome WebDriver 实例
        self.driver = webdriver.Chrome(service=service, options=options)
        # 窗口最大化
        self.driver.maximize_window()


    def login(self, page_url, btn_class):
        '''
        模拟点击按钮
        :param page_url: 测试网站
        :param btn_class: 按钮的class
        :return:
        '''
        # 打开网址
        self.driver.get(page_url)
        # 滚动页面滑动条，让滑块显示出来
        js = 'document.documentElement.scrollTop=200'
        self.driver.execute_script(js)

        # 等待某个条件成立时继续执行，否则在达到最大时长时抛超时异常
        wait = WebDriverWait(self.driver, 10)

        # 等待按钮可以被点击
        slider_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, btn_class)))
        # 点击按钮，触发滑块
        slider_element.click()

    #TODO 获取图片并保存
    def get_and_save_img(self, css_selector, fpath):
        # 等待某个条件成立时继续执行，否则在达到最大时长时抛超时异常
        wait = WebDriverWait(self.driver, 10)
        img_url = wait.until(lambda x: x.find_element(By.CSS_SELECTOR, css_selector)).get_attribute('src')
        # 判断文件夹是否存在不存在则创建'
        os.makedirs('./image/', exist_ok=True)
        with open(fpath, 'wb') as f:
            resp = requests.get(img_url)
            f.write(resp.content)

    # TODO 计算移动距离
    def FindPic(self, target='big.png', template='small.png'):
        target_rgb = cv2.imread(target)
        target_gray = cv2.cvtColor(target_rgb, cv2.COLOR_RGB2GRAY)
        template_rgb = cv2.imread(template, 0)
        res = cv2.matchTemplate(target_gray, template_rgb, cv2.TM_CCOEFF_NORMED)
        value = cv2.minMaxLoc(res)
        print(value)
        return value[3][0]

    # TODO 获取滑块需要滑动的距离
    def get_distance(self):
        distance = self.FindPic(sl_img_path, bg_img_path)
        print("本地图片需要滑动的距离：{}".format(distance))
        return distance

    def get_move(self, distance, btn_class):
        wait = WebDriverWait(self.driver, 10)
        ele = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, btn_class)))
        # 实例化对象
        action = ActionChains(self.driver)
        # 拖动滑块
        action.drag_and_drop_by_offset(ele, xoffset=distance, yoffset=0).perform()

    def cal_trace(self,offset):
        trace = [1]
        split = 0.7
        speedup = round(offset * split)
        slowdown = round(offset * (1 - split))

        while sum(trace) < speedup:
            trace.append(trace[-1] + 1)

        rear = [trace[-1] - 1]
        while sum(rear) < slowdown:
            rear.append(rear[-1] - 1)

        trace += rear
        div = offset - sum(trace)
        if div != 0:
            trace.append(div)

        return trace

    def get_move_pro(self, trace, btn_class):
        wait = WebDriverWait(self.driver, 10)
        ele = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, btn_class)))
        # 实例化对象
        action = ActionChains(self.driver)
        # 按下滑块按钮并保持
        action.click_and_hold(ele)
        for pace in trace:
            action.move_by_offset(xoffset=pace, yoffset=0)
        # 释放鼠标（按钮）
        action.release()
        # 执行行动链
        action.perform()

    def get_movepro(self, distance):
        '''
        :param distance: 小图在大图中缺口位置
        :return:
        '''
        # 获取小滑块的位置
        lo = self.driver.find_element("css selector", '.yidun_jigsaw').location

        x = lo['x'] * 1.99 + 30
        y = lo['y'] * 1.99 + 160 + 30 + 80

        #  定位鼠标到指定小滑块中心点位置，然后按下
        pyautogui.mouseDown(x, y)
        #  滑过头
        pyautogui.moveTo(x + distance + 20, y + 10, duration=0.3)
        #  滑回来
        pyautogui.moveTo(x + distance - 10, y - 5, duration=0.3)
        # 滑到指定位置
        pyautogui.moveTo(x + distance, y, duration=0.3)
        # 松开鼠标
        pyautogui.mouseUp()
        time.sleep(2)


    def fail_run(self, bg_img_class, bg_img_path, sl_img_class, sl_img_path, btn_class):
        while True:
            self.get_and_save_img(bg_img_class, bg_img_path)
            self.get_and_save_img(sl_img_class, sl_img_path)
            distance =  self.get_distance() + 10
            self.get_move(distance, btn_class)

            time.sleep(1)
            loc = ("css selector", bg_img_class)
            wait =  WebDriverWait(self.driver, timeout=3, poll_frequency=0.5)
            size = wait.until(lambda x: x.find_element(*loc)).size
            # 当验证码背景图大小为 0 时候就是破解成功了，就不用重试了
            if size.get('width') < 1:
                break
        # 成功后关闭浏览器
        self.driver.quit()
        print('验证成功')



if __name__ == '__main__':
    '''初始化'''
    page_url = 'https://dun.163.com/trial/jigsaw'
    # 滑块按钮class
    btn_class = '.yidun_slider.yidun_slider--hover'
    # 背景图class
    bg_img_class = '.yidun_bg-img'
    # 滑块图class
    sl_img_class = '.yidun_jigsaw'
    #  背景图本地保存路径
    bg_img_path = './image/background.png'
    # 滑块图本地保存路径
    sl_img_path = './image/slider.png'

    obj = Dun03Chufashi()
    obj.login(page_url, btn_class)
    obj.get_and_save_img(bg_img_class, bg_img_path)
    obj.get_and_save_img(sl_img_class, sl_img_path)
    disance = obj.get_distance()
    disance =disance*1.99
    print(disance)
    obj.get_movepro(disance)
    # obj.fail_run(bg_img_class, bg_img_path, sl_img_class, sl_img_path, btn_class)
